/*
 * LocalScaleRotationInfoPanel.java
 *
 * Created on August 16, 2005, 9:12 AM
 */

package ika.gui;

import ika.map.tools.*;
import java.awt.geom.*;
import java.text.*;
import ika.mapanalyst.Manager;
import ika.mapanalyst.LinkManager;
import ika.mapanalyst.Isolines;

/**
 *
 * @author  jenny
 */
public class LocalScaleRotationInfoPanel
        extends javax.swing.JPanel
        implements MapToolMouseMotionListener {
    
    private Manager manager;
    
    private static final DecimalFormat angleFormatter =
            new DecimalFormat("###,##0.0");
    private static final DecimalFormat scalePercentageFormatter =
            new DecimalFormat("(-##0.0%);(+##0.0%)");
    
    /** Creates new form LocalScaleRotationInfoPanel */
    public LocalScaleRotationInfoPanel() {
        initComponents();
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        scaleLabel = new javax.swing.JLabel();
        rotationLabel = new javax.swing.JLabel();
        scaleTextLabel = new javax.swing.JLabel();
        rotationTextLabel = new javax.swing.JLabel();

        setLayout(new java.awt.GridBagLayout());

        scaleLabel.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
        scaleLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        scaleLabel.setToolTipText("Scale at the mouse pointer. Only available for the old map.");
        scaleLabel.setPreferredSize(new java.awt.Dimension(110, 13));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        add(scaleLabel, gridBagConstraints);

        rotationLabel.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
        rotationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        rotationLabel.setToolTipText("Rotation at the mouse pointer. Only available for the old map.");
        rotationLabel.setPreferredSize(new java.awt.Dimension(110, 13));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        add(rotationLabel, gridBagConstraints);

        scaleTextLabel.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
        scaleTextLabel.setText("Local Scale : ");
        scaleTextLabel.setToolTipText("Scale at the mouse pointer. Only available for the old map.");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);
        add(scaleTextLabel, gridBagConstraints);

        rotationTextLabel.setFont(new java.awt.Font("Lucida Grande", 0, 10)); // NOI18N
        rotationTextLabel.setText("Local Rotation : ");
        rotationTextLabel.setToolTipText("Rotation at the mouse pointer. Only available for the old map.");
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 0);
        add(rotationTextLabel, gridBagConstraints);
    }// </editor-fold>//GEN-END:initComponents
    
    public void mouseMoved(java.awt.geom.Point2D.Double point, MapComponent mapComponent) {
        try {
            // only display for old map
            final boolean forOldMap = true;
            
            // transformation must be valid to compute local scale and rotation
            ika.transformation.Transformation transformation = this.manager.getTransformation();
            if (transformation == null
                    || transformation.isInitialized() == false) {
                return;
            }
            
            final double x = point.getX();
            final double y = point.getY();
            float[] scaleRot = new float[2];
                
            final double mapScale = transformation.getScale(true);

            // compute a local transfomormation for every mouse position.
            // this runs sufficently fast on modern computers.
            // we could instead extract the values with isolines.getCachedScaleAndRotation
            // this would returned rotation values that are not interpolated (values
            // "jump" between cells of the underlaying grid).
            if (!this.computeScaleRot(scaleRot, x, y, mapScale, forOldMap)) {
                this.scaleLabel.setText("-");
                this.rotationLabel.setText("-");
            } else {
                // write scale to GUI
                final float scale = scaleRot[0];
                String scaleStr = ika.utils.NumberFormatter.formatScale(null, scale, true);
                final double relScale = (mapScale - scale) / mapScale;
                String relScaleStr = scalePercentageFormatter.format(relScale);
                scaleStr += " " + relScaleStr;
                this.scaleLabel.setText(scaleStr);
                
                // write angle to GUI
                float azimuth = scaleRot[1];
                String suffix = "[cw]";
                if (azimuth < 0)
                    azimuth += 360;
                if (azimuth > 180) {
                    azimuth = 360 - azimuth;
                    suffix = "[ccw]";
                }
                String angleStr = angleFormatter.format(azimuth);
                this.rotationLabel.setText("<HTML>"+angleStr+"&#176 "+suffix+"</HTML>");
            }
        } catch (Exception exc) {
            this.scaleLabel.setText("-");
            this.rotationLabel.setText("-");
        }
    }
    
    private boolean computeScaleRot(float[] scaleRot,
            double x, double y, double mapScale, boolean forOldMap) {
        
        try {
            LinkManager linkManager = this.manager.getLinkManager();
            final double[][][] oldNewPts = linkManager.getLinkedPointsCopy();
            if (oldNewPts == null)
                return false;
            
            final int nbrPts = oldNewPts[0].length;
            if (nbrPts < 2)
                return false;
            
            final double[][] ptsOld = oldNewPts[0];
            final double[][] ptsNew = oldNewPts[1];
            
            Isolines isolines = this.manager.getIsolines();
            if (forOldMap) {
                // test if point is inside convex hull around points
                double[][] hull = this.manager.getLinkManager().getOldPointsHull();
                if (!ika.utils.GeometryUtils.pointInPolygon(x, y, hull))
                    return false;
                
                Rectangle2D boundsOldMap = linkManager.getOldPointsGeoSet().
                        getBounds2D();
                isolines.computeScaleAndRotation(x, y,
                        ptsNew, ptsOld, boundsOldMap, mapScale, scaleRot);
            }/* not needed since only for old map else {
                Rectangle2D boundsNewMap = linkManager.getNewPointsGeoSet().
                        getBounds2D();
                isolines.computeScaleAndRotation(x, y,
                        ptsOld, ptsNew, boundsNewMap, mapScale, scaleRot);
            }*/
            
            if (Float.isNaN(scaleRot[0]) || Float.isNaN(scaleRot[1]))
                return false;
            
            // invert the scale
            if (forOldMap) {
                scaleRot[0] = 1.f / scaleRot[0];
                scaleRot[1] = -scaleRot[1];
            }
            
            return true;
        } catch (Exception exc) {
            return false;
        }
    }
    
    public Manager getManager() {
        return this.manager;
    }
    
    public void setManager(Manager manager) {
        this.manager = manager;
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel rotationLabel;
    private javax.swing.JLabel rotationTextLabel;
    private javax.swing.JLabel scaleLabel;
    private javax.swing.JLabel scaleTextLabel;
    // End of variables declaration//GEN-END:variables
    
}
